package com.deer.wms.ware.task.web;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.deer.wms.base.system.constant.BaseSystemConstant;
import com.deer.wms.base.system.model.Cell.CellInfo;
import com.deer.wms.base.system.model.Pack.PackDetail;
import com.deer.wms.base.system.model.erp.ErpOutConstant;
import com.deer.wms.base.system.service.CellInfoService;
import com.deer.wms.base.system.service.PackDetailService;
import com.deer.wms.intercept.annotation.User;
import com.deer.wms.intercept.common.data.CurrentUser;
import com.deer.wms.inventory.constant.InventoryConstant;
import com.deer.wms.inventory.model.Inventory.Inventory;
import com.deer.wms.inventory.model.Inventory.InventoryCriteria;
import com.deer.wms.inventory.model.Inventory.InventorySelectDto;
import com.deer.wms.inventory.model.Inventory.InventoryTransact;
import com.deer.wms.inventory.service.InventoryService;
import com.deer.wms.inventory.service.InventoryTransactService;
import com.deer.wms.inventory.service.SerialNoService;
import com.deer.wms.project.root.core.result.CommonCode;
import com.deer.wms.project.root.core.result.Result;
import com.deer.wms.project.root.core.result.ResultGenerator;
import com.deer.wms.project.root.exception.ServiceException;
import com.deer.wms.project.root.util.DateUtils;
import com.deer.wms.project.root.util.MyUtils;
import com.deer.wms.project.root.util.StringUtil;
import com.deer.wms.project.root.util.StringUtils;
import com.deer.wms.system.manage.constant.SystemManageConstant;
import com.deer.wms.system.manage.model.user.UserInfo;
import com.deer.wms.system.manage.service.CellLedService;
import com.deer.wms.system.manage.service.CodeRuleService;
import com.deer.wms.system.manage.service.UserInfoService;
import com.deer.wms.system.manage.service.ValidatorService;
import com.deer.wms.ware.task.constant.WareTaskConstant;
import com.deer.wms.ware.task.dao.PickTaskMapper;
import com.deer.wms.ware.task.model.Box.BoxDetail;
import com.deer.wms.ware.task.model.SO.DeliveryData;
import com.deer.wms.ware.task.model.SO.Merge;
import com.deer.wms.ware.task.model.SO.SoDetail;
import com.deer.wms.ware.task.model.SO.SoMaster;
import com.deer.wms.ware.task.model.Wave.WaveDetail;
import com.deer.wms.ware.task.model.out.OutMaster;
import com.deer.wms.ware.task.model.pickTask.*;
import com.deer.wms.ware.task.service.PickTaskService;
import com.deer.wms.ware.task.service.SoDetailService;
import com.deer.wms.ware.task.service.SoMasterService;
import com.deer.wms.ware.task.service.WaveDetailService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * @author guo
 * @since 2020/02/02
 */
@RestController
@RequestMapping("/pick/tasks")
public class PickTaskController {

    @Autowired
    private PickTaskService pickTaskService;
    @Autowired
    private PickTaskMapper pickTaskMapper;
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private SoDetailService soDetailService;
    @Autowired
    private SoMasterService soMasterService;
    @Autowired
    private WaveDetailService waveDetailService;
    @Autowired
    private PackDetailService packDetailService;
    @Autowired
    private InventoryTransactService inventoryTransactService;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private CellInfoService cellInfoService;
    @Autowired
    private CodeRuleService codeRuleService;

    @PostMapping
    public Result add(@RequestBody PickTask pickTask) {
        pickTaskService.save(pickTask);
        return ResultGenerator.genSuccessResult();
    }

    @PostMapping("/detail")
    public Result detail(@RequestBody PickTaskCriteria bo) {
        List<PickTaskDto> pickTaskDtos = pickTaskService.findList(bo);
        List<PickTaskDto> collect = pickTaskDtos.stream().filter(pickTaskDto -> pickTaskDto.getState() < WareTaskConstant.PICK_STATE_ALLPICK).collect(Collectors.toList());
        if (collect.size() == 0) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "该容器已拣货完毕");
        }

        if (collect.size() >= 2) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "拣货数据存在重复，请联系管理员");
        }
        PickTaskDto pickTaskDto = null;
        if (pickTaskDtos.size() == 1) {
            pickTaskDto = collect.get(0);
            if (pickTaskDto.getPickQuantity().equals(pickTaskDto.getReviewQuantity())) {
                throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "该容器已拣货完毕");
            }
        }

        return ResultGenerator.genSuccessResult(pickTaskDto);
    }

    /**
     * 手工分配库存
     * @param createPickTask
     * @return
     */
    @PostMapping("/recommend/manual")
    @Transactional
    public Result manualCreatePickTask(@RequestBody CreatePickTask createPickTask) {
        if (createPickTask.getBillNo().equals("") || createPickTask.getSoDetailId() == null || createPickTask.getCreatePickTaskDetails().size() <= 0) {
            return ResultGenerator.genFailResult(CommonCode.PARAMETER_ERROR);
        }
        List<PickTaskDto> list = pickTaskService.findList(new PickTaskCriteria(createPickTask.getSoDetailId(), 4));
        if (list.size() > 0) {
            return ResultGenerator.genFailResult(CommonCode.PICK_TASK_ALREADY_EXIST);
        }
        SoDetail soDetail = soDetailService.getById(createPickTask.getSoDetailId());
        SoMaster soMaster = soMasterService.findBy("bill_no", createPickTask.getBillNo());

        //分配数量
        double allottedQuantity = 0;
        for (CreatePickTaskDetail createPickTaskDetail : createPickTask.getCreatePickTaskDetails()) {
            InventorySelectDto inventorySelectDto = inventoryService.findByInventoryId(new InventoryCriteria(createPickTaskDetail.getInventoryId())).get(0);
            PackDetail packDetail = packDetailService.getById(soDetail.getPackDetailId());
            //拣货任务的单位
//            PackDetail packDetailPick = packDetailService.getById(createPickTaskDetail.getPackDetailId());
//            if (packDetailPick == null){
//                throw new ServiceException(CommonCode.SYSTEM_ERROR,"拣货任务的单位为null");
//            }
            /**
             * 涉及到转换率
             */
            double quantity = MyUtils.calculateDivide(soDetail.getPackDetailId(), inventorySelectDto.getPackDetailId(), createPickTaskDetail.getPickQuantity(), packDetail.getTransRatio());
            inventorySelectDto.setAllotQuantity((inventorySelectDto.getAllotQuantity() == null ? 0.0 : inventorySelectDto.getAllotQuantity()) + quantity);
            inventoryService.updateById(inventorySelectDto);
            PickTask pickTask = new PickTask(
                    soDetail.getSoDetailId(),
                    soMaster.getSoMasterId(),
                    soMaster.getWareId(),
                    soMaster.getWareName(),
                    soMaster.getOrganizationId(),
                    soMaster.getOrganizationName(),
                    inventorySelectDto.getAreaCode(),
                    inventorySelectDto.getAreaName(),
                    inventorySelectDto.getShelfCode(),
                    inventorySelectDto.getShelfName(),
                    inventorySelectDto.getCellCode(),
                    inventorySelectDto.getCellName(),
                    inventorySelectDto.getItemCode(),
                    inventorySelectDto.getItemName(),
                    inventorySelectDto.getBatchId(),
                    inventorySelectDto.getBatchName(),
                    inventorySelectDto.getBoxCode(),
                    inventorySelectDto.getLpn(),
                    soDetail.getPackDetailId(),
                    soDetail.getPackDescribe(),
                    createPickTaskDetail.getPickQuantity(),
                    0,
                    inventorySelectDto.getInventoryId(),
                    1,
                    soDetail.getImgUrl()
                    );
            pickTask.setSoMasterCode(soMaster.getBillNo());
            pickTask.setPickTaskCode(codeRuleService.generateCodeByRedis(SystemManageConstant.CODE_RULE_PICK));
            pickTaskService.save(pickTask);
            allottedQuantity += createPickTaskDetail.getPickQuantity();
            Integer invenotryId =createPickTaskDetail.getInventoryId();
            Inventory inventory = inventoryService.getById(invenotryId);
            inventory.setAllotQuantity(createPickTaskDetail.getPickQuantity());
        }
        soDetail.setAllottedQuantity(allottedQuantity+soDetail.getAllottedQuantity());
        soDetail.setState(WareTaskConstant.OUT_STATE_DOING);
        soMaster.setState(WareTaskConstant.OUT_STATE_DOING);
        soDetailService.updateById(soDetail);
        soMasterService.updateById(soMaster);

        return ResultGenerator.genSuccessResult();
    }

    /**
     * 自动分配库存
     * @param merge 合并的SO单号
     * @return Result
     */
    @PostMapping("/recommend/auto")
    public Result autoCreatePickTask(@RequestBody Merge merge, @ApiIgnore @User CurrentUser currentUser) {
        List<SoMaster> soMasters = soMasterService
                .list(new QueryWrapper<SoMaster>().in("bill_no", merge.getBillNos()));

        //校验SO的状态，只允许未关闭的单据能推荐生成拣货任务
        for (SoMaster soMaster : soMasters) {
            if (ObjectUtil.notEqual(soMaster.getState(), WareTaskConstant.OUT_STATE_CLOSE)) {
                pickTaskService.createPickTask(soMaster, currentUser);
            }
        }
        return ResultGenerator.genSuccessResult();
    }

    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {
        pickTaskService.removeById(id);
        return ResultGenerator.genSuccessResult();
    }

    @PostMapping("/update")
    public Result update(@RequestBody PickTask pickTask) {
        pickTaskService.updateById(pickTask);
        return ResultGenerator.genSuccessResult();
    }

    @GetMapping("/{id}")
    public Result detail(@PathVariable Integer id) {
        PickTask pickTask = pickTaskService.getById(id);
        return ResultGenerator.genSuccessResult(pickTask);
    }

    @GetMapping("/list")
    public Result list(PickTaskCriteria criteria) {
        StringUtil.trimObjectStringProperties(criteria);
        PageHelper.startPage(criteria.getPageNum(), criteria.getPageSize());
        List<PickTaskDto> list = pickTaskService.findList(criteria);
        PageInfo pageInfo = new PageInfo(list);
        return ResultGenerator.genSuccessResult(pageInfo);
    }

    @GetMapping("/findBySoMasterId")
    public Result findBySoMasterId(PickTaskCriteria criteria) {
        StringUtil.trimObjectStringProperties(criteria);
        PageHelper.startPage(criteria.getPageNum(), criteria.getPageSize());
        List<PickTaskDto> list = pickTaskService.findByBillNo(criteria);
        PageInfo pageInfo = new PageInfo(list);
        return ResultGenerator.genSuccessResult(pageInfo);
    }

    @GetMapping("/findByWaveDetailId")
    public Result findByWaveDetailId(PickTaskCriteria criteria, @ApiIgnore @User CurrentUser currentUser) {
        PageHelper.startPage(criteria.getPageNum(), criteria.getPageSize());

        //首选需要判定波次明细是否已经完全推荐，因为存在波次部分推荐的情况
        WaveDetail waveDetail = waveDetailService.getById(criteria.getWaveDetailId());
        if (WareTaskConstant.WAVE_STATE_PICKING.equals(waveDetail.getState())) {
            // 若没有完全推荐，则需要根据库存重新推荐
            UserInfo wareUser = userInfoService.getById(waveDetail.getPickUserId());
            waveDetailService.suggestForPick(Collections.singletonList(waveDetail), wareUser, currentUser);
        }

        //获取当前波次明细下的所有拣货任务
        List<PickTaskDto> list = pickTaskService.findByWaveDetail(criteria.getWaveDetailId());
        PageInfo pageInfo = new PageInfo(list);
        return ResultGenerator.genSuccessResult(pageInfo);
    }

    @GetMapping("/findByDetailId")
    public Result findByDetailId(@RequestParam Integer soDetailId) {
        List<PickTask> list = pickTaskService.findBySoDetailId(soDetailId);
        return ResultGenerator.genSuccessResult(list);
    }

    @GetMapping("/allotTask")
    public Result allotTask(PickTaskCriteria criteria, @ApiIgnore @User CurrentUser currentUser) {
        StringUtil.trimObjectStringProperties(criteria);
        // criteria.setWaveCode(criteria.getWaveCode().trim());
        PageHelper.startPage(criteria.getPageNum(), criteria.getPageSize());
        criteria.setUserId(currentUser.getUserId());
        List<PickTaskDto> list = pickTaskService.allotTask(criteria);
        for (PickTaskDto pickTask:list  ) {
            if(pickTask.getAllotUserId()==null){
                pickTask.setAllotTime(DateUtils.getNowDateTimeString());
                pickTask.setAllotUserId(currentUser.getUserId());
                pickTask.setAllotUserName(currentUser.getUserName());
                pickTaskService.updateById(pickTask);
            }
        }
        PageInfo pageInfo = new PageInfo(list);
        return ResultGenerator.genSuccessResult(pageInfo);
    }

    @GetMapping("/boxingList")
    public Result boxingList(PickTaskCriteria criteria) {
        PageHelper.startPage(criteria.getPageNum(), criteria.getPageSize());
        List<PickTaskDto> list = new ArrayList<>();
        if (criteria.getTag() == 1) {
            list = pickTaskService.findBySo(criteria.getBillNo());

        } else if (criteria.getTag() == 2) {
            list = pickTaskService.findByWaveDetail(criteria.getWareId());
        }
        PageInfo pageInfo = new PageInfo(list);
        return ResultGenerator.genSuccessResult(pageInfo);
    }

    @PostMapping("/findFirst")
    public Result findFirst(@RequestBody PickTaskCriteria criteria) {
        PageHelper.startPage(criteria.getPageNum(), criteria.getPageSize());
        List<PickTaskDto> list = pickTaskService.findFirst(criteria);
        PageInfo pageInfo = new PageInfo(list);
        return ResultGenerator.genSuccessResult(pageInfo);
    }

    @ApiOperation(value = "取消拣货任务", notes = "只允许修改新建状态的拣货任务。改变拣货任务状态，回写出库任务/库存的分配数量")
    @PostMapping("/cancelPickTask")
    @Transactional
    public Result cancelPickTask(@RequestBody PickTaskCriteria pickTaskCriteria) {
        List<PickTaskDto> list = pickTaskService.findList(pickTaskCriteria);
        for (PickTaskDto pickTask : list) {
            if (ObjectUtil.notEqual(pickTask.getState(), WareTaskConstant.PICK_STATE_PROCESSING)) {
                throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "只允许关闭新建状态的拣货任务!");
            }
            pickTaskService.cancelPickTask(pickTaskService.getById(pickTask.getPickTaskId()));
        }
        return ResultGenerator.genSuccessResult();
    }




    @PostMapping("/warePickTask")
    public Result warePickTask(@RequestBody PickTaskCriteria criteria, @ApiIgnore @User CurrentUser currentUser) {
        List<PickTaskDto> list = pickTaskService.findList(criteria);
        return ResultGenerator.genSuccessResult();
    }

    /**
     * 按订单复核
     *
     * @param boxDetail
     * @return
     */
    @PostMapping("/checkBySo")
    public Result checkBySo(@RequestBody BoxDetail boxDetail) {

        String time = DateUtils.getNowDateTimeString();

        PickTask pickTask = pickTaskService.getById(boxDetail.getPickTaskId());
        pickTask.setReviewQuantity(pickTask.getReviewQuantity() + boxDetail.getQuantity());
        pickTaskService.updateById(pickTask);

        SoDetail soDetail = soDetailService.getById(boxDetail.getSoDetailId());
        soDetail.setDeliveryQuantity(soDetail.getDeliveryQuantity() + boxDetail.getQuantity());
        soDetailService.updateById(soDetail);

        SoMaster soMaster = soMasterService.getById(boxDetail.getSoMasterId());
        soMaster.setActualDeliveryTime(time);
        soMasterService.updateById(soMaster);
        return ResultGenerator.genSuccessResult();
    }


    @ApiOperation(value = "批量发货", notes = "批量发货")
    @PostMapping("/delivery")
    public Result delivery(@RequestBody DeliveryData deliveryData) {
        for (int i = 0; i < deliveryData.getPickTasks().size(); i++) {
            //step1.生成库存事务
            PickTask pickTask = deliveryData.getPickTasks().get(i);
            InventoryTransact inventoryTransact = new InventoryTransact();
            inventoryTransact.setTransactType(InventoryConstant.SERIALNO_OUT);
            inventoryTransact.setFromBatchId(pickTask.getBatchId());
            inventoryTransact.setFromBatchName(pickTask.getBatchName());
            inventoryTransact.setWareId(pickTask.getWareId());
            inventoryTransact.setWareName(pickTask.getWareName());
            inventoryTransact.setToCellCode(pickTask.getToCellCode());
            inventoryTransact.setToBatchId(pickTask.getBatchId());
            inventoryTransact.setToBatchName(pickTask.getBatchName());
            inventoryTransact.setItemCode(pickTask.getItemCode());
            inventoryTransact.setItemName(pickTask.getItemName());
            inventoryTransact.setToBoxCode(pickTask.getBoxCode());
            inventoryTransact.setToPackDetailId(pickTask.getPackDetailId());
            inventoryTransact.setToPackDescribe(pickTask.getPackDescribe());
            inventoryTransact.setToTransRatio(0.0);
            inventoryTransact.setCreateUserId(pickTask.getCheckUserId());
            inventoryTransact.setCreateUserName(pickTask.getCheckUserName());
            inventoryTransact.setCreateTime(pickTask.getCheckTime());
            inventoryTransact.setToQuantity(pickTask.getPickQuantity());
            inventoryTransact.setToOrganizationId(pickTask.getOrganizationId());
            inventoryTransact.setToOrganizationName(pickTask.getOrganizationName());
            inventoryTransactService.save(inventoryTransact);

            //step2.修改SO明细的状态 部分发货、全部发货
            Integer soDetailId = pickTask.getSoDetailId();
            SoDetail soDetail = soDetailService.getById(soDetailId);
            soDetail.setDeliveryQuantity(pickTask.getPickQuantity());
            if (soDetail.getDeliveryQuantity().equals(soDetail.getOrderQuantity())) {
                soDetail.setState(2); //全部发货
            } else {
                soDetail.setState(1); //部分发货

            }
            soDetailService.updateById(soDetail);

            inventoryTransact.setDetailNo(soDetail.getDetailNo());
            inventoryTransactService.updateById(inventoryTransact);

            //step3.修改拣货任务状态
            pickTask.setState(WareTaskConstant.PICK_STATE_OUTED);
            pickTaskService.updateById(pickTask);

            //step4.修改库存
            Integer inventoryId = pickTask.getInventoryId();
            Inventory inventory = inventoryService.getById(inventoryId);
            inventory.setAllotQuantity(inventory.getAllotQuantity() - pickTask.getPickQuantity());
            inventory.setQuantity(inventory.getQuantity() - pickTask.getPickQuantity());
            inventoryService.updateById(inventory);
            if (inventory.getQuantity() == 0) {
                inventoryService.removeById(inventoryId);
            }

            //step5.修改so单状态
            List<SoDetail> soDetailList = soDetailService.findByBillNo(soDetail.getBillNo());
            Boolean soDelivery = true;
            SoMaster soMaster = soMasterService.findBy("bill_no", soDetail.getBillNo());
            for (SoDetail soDetail1 : soDetailList) {
                if (soDetail1.getState() != 3) {
                    soDelivery = false;
                }
                soMaster.setState(7);//部分发货
                soMasterService.updateById(soMaster);
            }
            if (soDelivery) {
                soMaster.setState(8);//全部发货
                soMasterService.updateById(soMaster);
            }
        }

        return ResultGenerator.genSuccessResult();
    }

    @GetMapping("/getPickTasksForSeeding")
    public Result getPickTasksForSeeding(String waveCode, @ApiIgnore @User CurrentUser currentUser) {
        if (currentUser == null) {
            return ResultGenerator.genFailResult(CommonCode.MISSING_PERMISSION_PARAMTER);
        }
        PickTaskCriteria criteria = new PickTaskCriteria();
        criteria.setWaveCode(waveCode);
        List<PickTaskDto> list = pickTaskService.findList(criteria);
        return ResultGenerator.genSuccessResult(new PageInfo(list));
    }
    @GetMapping("/findByWaveMasterId")
    public Result findByWaveMasterId(PickTaskCriteria criteria, @ApiIgnore @User CurrentUser currentUser) {
        if (currentUser == null) {
            return ResultGenerator.genFailResult(CommonCode.MISSING_PERMISSION_PARAMTER);
        }
        PageHelper.startPage(criteria.getPageNum(), criteria.getPageSize());

        List<PickTaskDto> list = pickTaskService.findByWaveMasterId(criteria);
        return ResultGenerator.genSuccessResult(new PageInfo(list));
    }
    @PostMapping("/getSeedingWallAlertInfo")
    public Result getSeedingWallAlertInfo(@RequestBody PickTaskCriteria criteria, @ApiIgnore @User CurrentUser currentUser) {
        if (currentUser == null) {
            return ResultGenerator.genFailResult(CommonCode.MISSING_PERMISSION_PARAMTER);
        }
        List<SeedingWallAlertInfo> list = pickTaskService.getSeedingWallAlertInfo(criteria);
        PageInfo pageInfo = new PageInfo(list);
        return ResultGenerator.genSuccessResult(pageInfo);
    }
    @Transactional
    @GetMapping("/updateSeededQuantity")
    public Result updateSeededQuantity(String soNo, String itemCode, Double quantity, Integer inventoryId, @ApiIgnore @User CurrentUser currentUser) {
        if (currentUser == null) {
            return ResultGenerator.genFailResult(CommonCode.MISSING_PERMISSION_PARAMTER);
        }
        PickTaskCriteria taskCriteria = new PickTaskCriteria();
        taskCriteria.setBillNo(soNo);
        taskCriteria.setItemCode(itemCode);
        taskCriteria.setInventoryId(inventoryId);
        List<PickTaskDto> pickTasks = pickTaskService.findList(taskCriteria);
        for (PickTask pickTask : pickTasks) {
            Double pickQuantity = pickTask.getPickQuantity();
            Double seededQuantity = pickTask.getSeededQuantity();
            Double neededQuantity = pickQuantity - seededQuantity;
            if (quantity > neededQuantity) {
                pickTask.setSeededQuantity(pickQuantity);
                quantity -= neededQuantity;
            } else if (quantity <= neededQuantity) {
                pickTask.setSeededQuantity(seededQuantity + quantity);
                pickTaskService.updateById(pickTask);
                break;
            }
            pickTaskService.updateById(pickTask);
        }
        return ResultGenerator.genSuccessResult();
    }

    @ApiOperation(value = "拣货确认", notes = "PDA")
    @ApiImplicitParams({@ApiImplicitParam(name = "access-token", value = "token", paramType = "header", dataType = "String", dataTypeClass = String.class, required = true)})
    @PostMapping("/commitPick")
    public Result commitPick(@RequestBody CommitPickTask commitPickTask, @ApiIgnore @User CurrentUser currentUser) {
        //校验 拣货任务状态
        Integer pickTaskId = commitPickTask.getPickTaskId();
        PickTask pickTask = pickTaskService.getById(pickTaskId);
        SoMaster soMaster = soMasterService.getById(pickTask.getSoMasterId());
        if (ObjectUtil.notEqual(pickTask.getState(), WareTaskConstant.PICK_STATE_PROCESSING)
                && ObjectUtil.notEqual(pickTask.getState(), WareTaskConstant.PICK_STATE_PARTPICK)) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "该拣货任务不为新建和部分拣货状态!");
        }
        //校验 是否低于计划数量
        if (pickTask.getPickQuantity() > commitPickTask.getPickQuantity()) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "拣货数量【" + commitPickTask.getPickQuantity() + "】不允许小于计划数量【" + pickTask.getPickQuantity() + "】!");
        }

        Inventory boxInv = inventoryService.getOneByField("box_code", pickTask.getBoxCode());
        if (boxInv.getQuantity() < commitPickTask.getPickQuantity()) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR,
                    "拣货数量【" + commitPickTask.getPickQuantity() + "】不允许大于库存数量【" + boxInv.getQuantity() + "】!");
        }

        //封装数据
        String toCellCode = commitPickTask.getToCellCode();
        if (StringUtils.isEmpty(toCellCode)) {
            toCellCode = cellInfoService.getSysJhCell(boxInv.getWareId());
        }
        pickTask.setToCellCode(toCellCode);
        pickTask.setToBoxCode(commitPickTask.getToBoxCode());
        //核心方法.拣货确认
        Integer invId = pickTaskService.commitPick(pickTask, commitPickTask.getPickQuantity(), currentUser);
        List<String> cellCodes = new ArrayList<>();
        cellCodes.add(boxInv.getCellCode());
        cellLedService.ledControl(cellCodes, null, -1L, 0);
        if (boxInv.getQuantity() > commitPickTask.getPickQuantity()) {
            //拣货数量小于包装数量，此时需要重新打印标签
            List<Inventory> invList = new ArrayList<>();
            //原来的库存
            boxInv.setQuantity(boxInv.getQuantity() - commitPickTask.getPickQuantity());
            invList.add(boxInv);
            //新增的库存
            Inventory newInv = new Inventory();
            BeanUtil.copyProperties(boxInv, newInv);
            PickTask newPickTask = pickTaskService.getById(pickTaskId);
            newInv.setBoxCode(newPickTask.getToBoxCode());
            newInv.setQuantity(commitPickTask.getPickQuantity());
            invList.add(newInv);
            return ResultGenerator.genSuccessResult(invList);
        }

        return ResultGenerator.genSuccessResult();
    }

    @ApiOperation(value = "拣货确认(不按拣货任务拣货)", notes = "PDA")
    @ApiImplicitParams({@ApiImplicitParam(name = "access-token", value = "token", paramType = "header", dataType = "String", dataTypeClass = String.class, required = true)})
    @PostMapping("/commitPickForChange")
    @Transactional
    public Result commitPickForChange(@RequestBody CommitPickTask commitPickTask, @ApiIgnore @User CurrentUser currentUser) {
        //Step1.校验
        Integer pickTaskId = commitPickTask.getPickTaskId();
        PickTask oldPickTask = pickTaskService.getById(pickTaskId);
        double oldUnPickedQty = oldPickTask.getPickQuantity() - oldPickTask.getReviewQuantity();
        if (ObjectUtil.notEqual(oldPickTask.getState(), WareTaskConstant.PICK_STATE_PROCESSING)
                && ObjectUtil.notEqual(oldPickTask.getState(), WareTaskConstant.PICK_STATE_PARTPICK)) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "该拣货任务不为新建和部分拣货状态!");
        }
        //校验 新的拣货追踪号库存  是否满足：物料相同，批次相同，数量大于拣货任务数量
        Inventory boxInv = inventoryService.getOneByField("box_code", commitPickTask.getNewBoxCode());
        if (ObjectUtil.notEqual(oldPickTask.getItemCode(), boxInv.getItemCode()) || ObjectUtil.notEqual(oldPickTask.getBatchName(), boxInv.getBatchName())) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "物料或批次与原任务不一致，请确认!");
        }
        if(boxInv.getAllotQuantity() > 0){
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "变更追踪号已被分配!");
        }
        if (boxInv.getQuantity() < commitPickTask.getPickQuantity()) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR,
                    "任务数量【" + commitPickTask.getPickQuantity() + "】不允许大于库存数量【" + boxInv.getQuantity() + "】!");
        }

        //校验 是否低于计划数量
//        if (oldUnPickedQty > commitPickTask.getPickQuantity()) {
//            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "拣货数量【" + commitPickTask.getPickQuantity() + "】不允许小于计划数量【" + oldUnPickedQty + "】!");
//        }


        SoDetail soDetail = soDetailService.getById(oldPickTask.getSoDetailId());
        SoMaster soMaster = soMasterService.findBy("bill_no", soDetail.getBillNo());
        //Step2.新增拣货任务   取消旧的拣货任务(旧的库存库存分配占用取消)
        if (oldUnPickedQty > commitPickTask.getPickQuantity()) {
            //没有被一次性捡完
            soDetail.setAllottedQuantity(soDetail.getAllottedQuantity() - commitPickTask.getPickQuantity());
            soDetailService.updateById(soDetail);
            oldPickTask.setPickQuantity(oldPickTask.getPickQuantity() - commitPickTask.getPickQuantity());
            pickTaskService.updateById(oldPickTask);
            Inventory inventory = inventoryService.getById(oldPickTask.getInventoryId());
            if(ObjectUtil.isNotNull(inventory)){
                inventory.setAllotQuantity(inventory.getAllotQuantity() - commitPickTask.getPickQuantity());
                inventoryService.updateById(inventory);
            }
        } else {
            pickTaskService.cancelPickTask(oldPickTask);
        }


        //分配数量
        InventorySelectDto inventorySelectDto = new InventorySelectDto();
        inventorySelectDto.setCellCode(boxInv.getCellCode());
        inventorySelectDto.setBatchId(boxInv.getBatchId());
        inventorySelectDto.setBatchName(boxInv.getBatchName());
        inventorySelectDto.setCellCode(boxInv.getCellCode());
        inventorySelectDto.setBoxCode(boxInv.getBoxCode());
        inventorySelectDto.setInventoryId(boxInv.getInventoryId());
        PickTask pickTask = new PickTask(soMaster, soDetail, inventorySelectDto);
        //实际拣货的数量
        pickTask.setPickQuantity(commitPickTask.getPickQuantity());
        pickTask.setPickTaskCode(codeRuleService.generateCodeByRedis(SystemManageConstant.CODE_RULE_PICK));
        pickTaskService.save(pickTask);

        boxInv.setAllotQuantity(commitPickTask.getPickQuantity());
        inventoryService.updateById(boxInv);

        soDetail.setAllottedQuantity(soDetail.getAllottedQuantity() + commitPickTask.getPickQuantity());
        soDetail.setState(WareTaskConstant.OUT_STATE_DOING);
        soMaster.setState(WareTaskConstant.OUT_STATE_DOING);
        soDetailService.updateById(soDetail);
        soMasterService.updateById(soMaster);


        //封装数据
        String toCellCode = commitPickTask.getToCellCode();
        if (StringUtils.isEmpty(toCellCode)) {
            toCellCode = cellInfoService.getSysJhCell(boxInv.getWareId());
        }
        oldPickTask.setToCellCode(toCellCode);
        oldPickTask.setToBoxCode(commitPickTask.getToBoxCode());

        //核心方法.拣货确认
        Integer invId = pickTaskService.commitPick(pickTask, commitPickTask.getPickQuantity(), currentUser);

        List<String> cellCodes = new ArrayList<>();
        cellCodes.add(boxInv.getCellCode());
        cellCodes.add(oldPickTask.getCellCode());
        cellLedService.ledControl(cellCodes, null, -1L, 0);

        if (boxInv.getQuantity() > commitPickTask.getPickQuantity()) {
            //拣货数量小于包装数量，此时需要重新打印标签
            List<Inventory> invList = new ArrayList<>();
            //原来的库存
            boxInv.setQuantity(boxInv.getQuantity() - commitPickTask.getPickQuantity());
            invList.add(boxInv);
            //新增的库存
            Inventory newInv = new Inventory();
            BeanUtil.copyProperties(boxInv, newInv);
            PickTask newPickTask = pickTaskService.getById(pickTaskId);
            newInv.setBoxCode(newPickTask.getToBoxCode());
            newInv.setQuantity(commitPickTask.getPickQuantity());
            invList.add(newInv);
            return ResultGenerator.genSuccessResult(invList);
        }

        return ResultGenerator.genSuccessResult();
    }

    @Autowired
    private CellLedService cellLedService;

    @ApiOperation(value = "波次拣货", notes = "PDA")
    @ApiImplicitParams({@ApiImplicitParam(name = "access-token", value = "token", paramType = "header", dataType = "String", dataTypeClass = String.class, required = true)})
    @PostMapping("/commitPick2")
    public Result commitPick2(@RequestBody CommitPickTask commitPickTask, @ApiIgnore @User CurrentUser currentUser) {
        //封装数据
        String toCellCode = commitPickTask.getToCellCode();
        if (StringUtils.isEmpty(toCellCode)) {
            toCellCode = cellInfoService.getSysJhCell(commitPickTask.getWareId());
        }
        //校验 拣货任务状态
        Integer inventoryId = commitPickTask.getInventoryId();
        Double pickQuantity = commitPickTask.getPickQuantity();
        PickTaskCriteria pickTaskCriteria = new PickTaskCriteria();
        pickTaskCriteria.setWaveDetailId(commitPickTask.getWaveDetailId());
        pickTaskCriteria.setInventoryId(commitPickTask.getInventoryId());
        List<PickTaskDto> pickTaskDtos = pickTaskService.findList(pickTaskCriteria);

        for (PickTaskDto pickTaskDto : pickTaskDtos) {
            if (pickQuantity == 0.0) {
                continue;
            }
            PickTask pickTask = pickTaskService.getById(pickTaskDto.getPickTaskId());
            pickTask.setToCellCode(toCellCode);
            Double qty = pickTask.getPickQuantity();
            if (qty > pickQuantity) {
                pickTaskService.commitPick(pickTask, pickQuantity, currentUser);
                pickQuantity = 0.0;
            } else {
                pickTaskService.commitPick(pickTask, qty, currentUser);
                pickQuantity -= qty;
            }
        }

        return ResultGenerator.genSuccessResult();
    }

    @ApiOperation(value = "发货复核", notes = "支持按单发货和波次发货两种场景")
    @GetMapping("/getBoxesForSend")
    @Transactional
    public Result getBoxesForSend(@RequestParam String boxCode) {
        //Step1.校验
        //判断库存，判断是否在发货区
        Inventory inventory = inventoryService.getOneByField("box_code", boxCode);
        if (ObjectUtil.isNull(inventory)) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "容器" + boxCode + "查询不到库存");
        }

        String cellCode = inventory.getCellCode();
        Integer cellType = cellInfoService.getCellType(cellCode, inventory.getWareId());
        if (ObjectUtil.notEqual(BaseSystemConstant.CELL_USE_TYPE_COLLECTION, cellType)) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "容器库存" + boxCode + "不在发货区");
        }
        //Step2.查询
        List<PickTask> list = new ArrayList<>();
        PickTask pickTask = pickTaskService.getOneByField("inventory_id", inventory.getInventoryId());
        if (ObjectUtil.isNotNull(pickTask.getSoMasterId())) {
            //按单发货逻辑
            SoMaster soMaster = soMasterService.getById(pickTask.getSoMasterId());
//            if (WareTaskConstant.SO_STATE_PICKED.equals(soMaster.getState())) {
//                list = pickTaskService.getListByField("so_master_id", soMaster.getSoMasterId());
//            }else {
//                throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "未全部拣货");
//            }

            LambdaQueryWrapper<PickTask> queryWrapper = new LambdaQueryWrapper<>();
             queryWrapper.eq(PickTask::getSoMasterId,soMaster.getSoMasterId())
            .and(
                w ->
                    w.eq(PickTask::getState,1)
                    .or()
                    .eq(PickTask::getState,2)
            );
            list.addAll(pickTaskMapper.selectList(queryWrapper));
//            list = pickTaskService.getListByField("so_master_id", soMaster.getSoMasterId());
            if (list.size() == 0){
                throw new ServiceException(CommonCode.SYSTEM_ERROR,"未生成发货区");
            }
            //用于前台显示对应的出库任务
            list.get(0).setMemo(soMaster.getBillNo());
        } else {
            //波次发货逻辑
            Integer pickUserId = pickTask.getPickUserId();
            //根据拣货人查询到执行中的波次明细
            QueryWrapper<WaveDetail> qw = new QueryWrapper<>();
            qw.eq("pick_user_id", pickUserId);
            qw.in("state", WareTaskConstant.WAVE_STATE_PICKING, WareTaskConstant.WAVE_STATE_ALL_ALOT);
            List<WaveDetail> waveDetails = waveDetailService.list(qw);
            List<Integer> waveIds = waveDetails.stream().map(WaveDetail::getWaveDetailId).collect(Collectors.toList());

            //找到波次明细对应的拣货任务
            QueryWrapper<PickTask> qw2 = new QueryWrapper<>();
            qw2.eq("state", WareTaskConstant.PICK_STATE_ALLPICK);
            qw2.in("wave_detail_id", waveIds);

            list = pickTaskService.list(qw2);
        }
        return ResultGenerator.genSuccessResult(list);
    }

    @GetMapping("/pickAndSendOut")
    @Transactional
    public Result pickAndSendOut(String  pickIds,Integer erpAreaId,@ApiIgnore @User CurrentUser currentUser) {
        if (ObjectUtil.isNull(currentUser)) {
            return ResultGenerator.genFailResult(CommonCode.MISSING_PERMISSION_PARAMTER);
        }

        List<PickTask> pickTasks = pickTaskService.listByIds(Arrays.asList(pickIds.split(",")));
        for (PickTask pickTask : pickTasks) {
            //特殊情况，拣货数量直接等于计划数量
            //这里也支持部分拣货的情况
            pickTask.setReviewQuantity(pickTask.getPickQuantity());
        }

        //扣减库存，生成出库单
        OutMaster outMaster = pickTaskService.pickAndSendOut(pickTasks, currentUser, erpAreaId);

        //出库单据回传erp
//        OrderToErpBO erpBean = this.getErpBean(outMaster);
//        pushErpService.pushIMBIll(erpBean);
        return ResultGenerator.genSuccessResult();
    }

}
